/*****************************************************************************/
/**
 *  @file   ImportStaggeredSPHFile.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "ImportStaggeredSPHFile.h"
#include "SPHFile.h"
#include <kvs/StructuredVolumeObject>
#include <kvs/Vector3>
#include <kvs/AnyValueArray>
#include <kvs/ValueArray>
#include <kvs/Assert>


namespace
{

kvs::Real32 Extrap(
    const size_t index0,
    const size_t index1,
    const size_t stride,
    const kvs::AnyValueArray& data )
{
    const size_t veclen = 3;
    const kvs::Real32 s0 = data.at<kvs::Real32>( index0 * veclen + stride );
    const kvs::Real32 s1 = data.at<kvs::Real32>( index1 * veclen + stride );
    return 1.5f * s0 - 0.5f * s1;
}

kvs::Real32 Interp(
    const size_t index0,
    const size_t index1,
    const size_t stride,
    const kvs::AnyValueArray& data )
{
    const size_t veclen = 3;
    const kvs::Real32 s0 = data.at<kvs::Real32>( index0 * veclen + stride );
    const kvs::Real32 s1 = data.at<kvs::Real32>( index1 * veclen + stride );
    return 0.5f * ( s0 + s1 );
}

kvs::ValueArray<kvs::Real32> ColocateFromStaggered2( const kvs::AnyValueArray& data, const kvs::Vector3ui& dim )
{
    const size_t veclen = 3;
    const size_t value_size = dim.x() * dim.y() * dim.z() * veclen;
    kvs::ValueArray<kvs::Real32> values( value_size );

    const size_t nnodes_per_slice = dim.x() * dim.y();
    const size_t nnodes_per_line = dim.x();
    for ( size_t k = 0, index = 0; k < dim.z(); k++ )
    {
        for ( size_t j = 0; j < dim.y(); j++ )
        {
            for ( size_t i = 0; i < dim.x(); i++, index++ )
            {
                const size_t u0 = i == 0 ? index : index - 1;
                const size_t u1 = i == 0 ? index + 1 : index;
                const kvs::Real32 u = i == 0 ? Extrap( u0, u1, 0, data ) : Interp( u0, u1, 0, data );

                const size_t v0 = j == 0 ? index : index - nnodes_per_line;
                const size_t v1 = j == 0 ? index + nnodes_per_line : index;
                const kvs::Real32 v = j == 0 ? Extrap( v0, v1, 1, data ) : Interp( v0, v1, 1, data );

                const size_t w0 = k == 0 ? index : index - nnodes_per_slice;
                const size_t w1 = k == 0 ? index + nnodes_per_slice : index;
                const kvs::Real32 w = k == 0 ? Extrap( w0, w1, 2, data ) : Interp( w0, w1, 2, data );

                values[ index * veclen + 0 ] = u;
                values[ index * veclen + 1 ] = v;
                values[ index * veclen + 2 ] = w;
            }
        }
    }

    return values;
}

}


namespace kvsbloodvis
{

namespace util
{

/*===========================================================================*/
/**
 *  @brief  Imports staggered SPH file as a structured volume object.
 *  @param  sph [in] SPH file
 *  @return structured volume object
 */
/*===========================================================================*/
kvs::StructuredVolumeObject ImportStaggeredSPHFile( const SPHFile& sph )
{
    KVS_ASSERT( sph.svType() == 2 );

    const size_t veclen = 3;
    const kvs::Vector3ui dim = sph.resolution();
    const kvs::ValueArray<kvs::Real32> values = ::ColocateFromStaggered2( sph.data(), dim );

    kvs::StructuredVolumeObject volume;
    volume.setGridType( kvs::StructuredVolumeObject::Uniform );
    volume.setVeclen( veclen );
    volume.setResolution( dim );
    volume.setValues( values );
    volume.updateMinMaxCoords();
    volume.updateMinMaxValues();

    return volume;
}

} // end of namespace util

} // end of namespace kvsbloodvis
